package zzzhc.image.recognize.nn;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.joone.io.MemoryInputSynapse;

public class NNInput {

	private List<NNInputItem> items = new ArrayList<NNInputItem>();

	private Map<Character, Integer> codeMap;

	public static NNInput loadFromFile(String path, int sampleNum)
			throws IOException {
		BufferedReader reader = new BufferedReader(new FileReader(path));
		NNInput input = new NNInput();
		String line;
		while ((line = reader.readLine()) != null) {
			String[] ss = line.split(";");
			if (sampleNum <= 0) {
				sampleNum = ss.length - 1;
			}
			NNInputItem item = new NNInputItem();
			double[] data = new double[sampleNum];
			for (int i = 0; i < sampleNum; i++) {
				data[i] = Double.parseDouble(ss[i]);
			}
			item.setData(data);
			item.setCode(ss[ss.length - 1].charAt(0));
			input.addItem(item);
		}

		return input;
	}

	public static NNInput loadFromFile(String path) throws IOException {
		return loadFromFile(path, -1);
	}

	public void addItem(NNInputItem item) {
		items.add(item);
	}

	public void addItem(double[] data, char code) {
		NNInputItem item = new NNInputItem(data, code);
		addItem(item);
	}

	public MemoryInputSynapse createInputSynapse() {
		MemoryInputSynapse inputSynapse = new MemoryInputSynapse();
		double[][] inputArray = new double[items.size()][];
		for (int i = 0; i < items.size(); i++) {
			inputArray[i] = items.get(i).getData();
		}
		inputSynapse.setAdvancedColumnSelector("1-" + getFetureNum());
		inputSynapse.setFirstRow(1);
		inputSynapse.setInputArray(inputArray);
		return inputSynapse;
	}

	public List<NNInputItem> getItems() {
		return items;
	}

	public int getCodeTypeNum() {
		Set<Character> codes = new HashSet<Character>();
		for (NNInputItem item : items) {
			codes.add(item.getCode());
		}
		return codes.size();
	}

	public int getFetureNum() {
		if (items.size() == 0) {
			return 0;
		} else {
			return items.get(0).getData().length;
		}
	}

	public int getPatterns() {
		return items.size();
	}

	public MemoryInputSynapse createDesireSynapse() {
		initCodeMap();
		MemoryInputSynapse inputSynapse = new MemoryInputSynapse();
		int codeSize = codeMap.size();
		double[][] inputArray = new double[items.size()][codeSize];
		for (int i = 0; i < items.size(); i++) {
			double[] data = new double[codeSize];
			int index = codeMap.get(items.get(i).getCode());
			for (int j = 0; j < codeSize; j++) {
				if (j == index) {
					data[j] = 1;
				} else {
					data[j] = 0;
				}
			}
			inputArray[i] = data;
		}
		inputSynapse.setAdvancedColumnSelector("1-" + codeSize);
		inputSynapse.setFirstRow(1);
		inputSynapse.setInputArray(inputArray);
		return inputSynapse;
	}

	private void initCodeMap() {
		Set<Character> codes = new HashSet<Character>();
		for (NNInputItem item : items) {
			codes.add(item.getCode());
		}
		List<Character> codeList = new ArrayList<Character>(codes);
		Collections.sort(codeList);
		codeMap = new HashMap<Character, Integer>();
		for (int i = 0; i < codeList.size(); i++) {
			codeMap.put(codeList.get(i), i);
		}
	}

	public Map<Character, Integer> getCodeMap() {
		initCodeMap();
		return codeMap;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("NNInput[\n");

		for (NNInputItem item : items) {
			for (double d : item.getData()) {
				sb.append(d).append(";");
			}
			sb.append(item.getCode()).append("\n");
		}

		sb.append("]\n");
		return sb.toString();
	}
}
